package com.aldobucchi.x.Array
{
	import com.aldobucchi.core.comparison.ComparisonUtil;
	import com.aldobucchi.core.comparison.result.ComparisonResult;
	import com.aldobucchi.core.comparison.result.ComparisonResults;
	import com.aldobucchi.core.comparison.simple.ISimpleComparator;
	import com.aldobucchi.x.Math.MathUtil;
	
	
	public class ArrayUtil
	{
		
		
		
		/**
		 * 
		 * Returns one random element from within the array
		 * 
		 * @param arr
		 * @return 
		 * 
		 */		
		public static function rand( arr:Array ):*
		{
			if ( arr.length == 0 )
				return undefined;
			return arr[ MathUtil.randInt( 0, arr.length - 1 ) ];
		}
		
		
		
		
		
		
		
		
		/**
		 * 
		 * Will compare every item in the array using the passed in comparator.
		 * They must all return EQUAL in order for this method to return EQUAL.
		 * 
		 * @param arr1
		 * @param arr2
		 * @param comparator
		 * @return 
		 * 
		 */		
		public static function compareEachElement( arr1:Array, arr2:Array, comparator:ISimpleComparator = null, recursive:Boolean = false ):ComparisonResult
		{
			// cheapest comparisons first
			if ( arr1 === arr2 )
				return 	ComparisonResults.EQUAL;			
		
			if ( arr1.length != arr2.length )
				return ComparisonResults.DIFFERENT;			


			var res:ComparisonResult;
			var length:int = arr1.length;
			
			for ( var i:int = 0; i<length; i++ )
			{
				var item1:* = arr1[ i ];
				var item2:* = arr2[ i ];
				if ( recursive && ( item1 is Array ) )
				{
					if ( ! ( item2 is Array ) )
						return ComparisonResults.DIFFERENT;
					// recursion
					res = compareEachElement( item1 as Array, item2 as Array, comparator, recursive );
					if ( ! res.isEqual )
						return res;						
				}
				else
				{
					res = ComparisonUtil.compare( item1, item2, comparator );
					if ( ! res.isEqual )
						return res;					
				}							
			}
			return ComparisonResults.EQUAL;
		}
		
		
		
		
		public static function contains( arr:Array, value:*, comparator:ISimpleComparator = null ):Boolean
		{
			return indexOf( arr, value, comparator ) != -1;	
		}
		
		
		
	
		public static function removeDuplicates( arr:Array, comparator:ISimpleComparator = null ):Array
		{
			var result:Array = new Array();
			for ( var i:int=0; i<arr.length; i++ )
				if ( indexOf( result, arr[i], comparator  ) == -1 )
					result.push( arr[i] );
			return result;
		}
		
		
		
	
		public static function indexOf( arr:Array, value:*, comparator:ISimpleComparator = null ):int
		{
			for ( var i:int=0; i<arr.length; i++ )
				if ( ComparisonUtil.compare( arr[i], value, comparator ).isEqual  )
					return i;
			return -1;
		}
		
		
		
		/**
		 * 
		 * Returns an array containing only the elements that occurr in both arrays
		 * 
		 * @param arr1
		 * @param arr2
		 * @param comparator
		 * @param removeDuplicates
		 * @return 
		 * 
		 */		
		public static function computeIntersection( arr1:Array, arr2:Array, comparator:ISimpleComparator = null, removeDuplicates:Boolean = true ):Array
		{
			var intersection:Array = new Array();
			for ( var i:int=0; i<arr1.length; i++ )
				if ( indexOf( arr2, arr1[ i ], comparator ) != -1 )
					intersection.push( arr1[ i ] );
			return removeDuplicates ? ArrayUtil.removeDuplicates( intersection, comparator ) : intersection ;
		}
		

		
		/**
		 * 
		 * Computes the difference between the two passed arrays
		 * 
		 * @param arr1
		 * @param arr2
		 * @param comparator
		 * @return [ onlyIn1, onlyIn2 ]
		 * 
		 */		
		public static function computeDelta( arr1:Array, arr2:Array, comparator:ISimpleComparator = null, removeDuplicates:Boolean = false ):Array
		{
			var onlyIn1:Array = [];
			var onlyIn2:Array = [];
			var item:*;
			
			var intersection:Array = computeIntersection( arr1, arr2, comparator, true );
			
			for each ( item in arr1 )
				if ( indexOf( intersection, item, comparator ) == -1 )
					onlyIn1.push( item );
			
			for each ( item in arr2 )
				if ( indexOf( intersection, item, comparator ) == -1 )
					onlyIn2.push( item );
			
			if ( removeDuplicates )
			{
				onlyIn1 = ArrayUtil.removeDuplicates( onlyIn1, comparator );
				onlyIn2 = ArrayUtil.removeDuplicates( onlyIn2, comparator );
			}
			
			
			return [ onlyIn1, onlyIn2 ];
		}
		
	}
	
}